package com.zzg.lucene.condition;

import java.io.IOException;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.WildcardQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;

public class SearcherUtil {
	private Directory directory;
	private IndexReader reader;
	private String[] ids = { "1", "2", "3", "4", "5", "6" };
	private String[] emails = { "aa@qq.com", "bb@sina.edu", "cc@yahu.org", "ss@sina.com", "dd@gmail.com",
			"ee@163.com" };
	private String[] content = { "welcom to visited the space,I like football", "hello boy, i like someone",
			"come on baby", "first blood", "I like football,I like football",
			"my girlfriend is so beatiful, every body like game" };
	private int[] attaches = { 2, 5, 6, 5, 8, 4 };
	private String[] names = { "tom", "jack", "goudan", "alibaba", "jerry", "kitty" };
	private Date[] dates = null;

	public SearcherUtil() {
		directory = new RAMDirectory();
		setDates();
		index();
	}

	public IndexSearcher getSearcher() {
		try {
			if (reader == null) {
				reader = DirectoryReader.open(directory);
			}
			return new IndexSearcher(reader);
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	// 精确匹配查询
	public void searchByTerm(String field, String name, int num)
			throws org.apache.lucene.queryparser.classic.ParseException {
		IndexSearcher searcher = getSearcher();
		QueryParser parser = new QueryParser(field, new StandardAnalyzer());
		Query query = parser.parse(name);

		try {
			TopDocs tds = searcher.search(query, num);// TopDocs封装搜索结果以及
														// ScoreDoc 的总数
			System.out.println("总共查询了： " + tds.totalHits);
			for (ScoreDoc sd : tds.scoreDocs) {// ScoreDoc提供对TopDocs中每条搜索结果的访问接口
				Document doc = searcher.doc(sd.doc);
				System.out.println("id号：" + doc.get("id") + "，名字：" + doc.get("name") + "，邮箱：" + doc.get("email")
						+ "，附件条数：" + doc.get("attach") + "，日期：" + doc.get("date"));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void index() {
		IndexWriter writer = null;
		try {
			writer = new IndexWriter(directory, new IndexWriterConfig(new StandardAnalyzer()));
			// 此方法可将索引全部清空
			writer.deleteAll();
			Document document = null;
			for (int i = 0; i < ids.length; i++) {
				document = new Document();
				// id需要存储，不需要加权、分词，email也需要存储，但不需要分词，有时候也需要加权
				// 对于内容，我们不需要存储和加权，但需要分词。而名字需要存储，不需要分词和加权
				// 这里我们先不对整型数据进行索引，后面再说
				document.add(new StringField("id", ids[i], Field.Store.YES));
				document.add(new StringField("email", emails[i], Field.Store.YES));
				document.add(new StringField("content", content[i], Field.Store.NO));
				document.add(new StringField("name", names[i], Field.Store.YES));

				// 为数字添加索引，第三个参数设置为true表示默认索引
				document.add(new IntPoint("attach", attaches[i]));

				// 为日期添加索引
				document.add(new NumericDocValuesField("date", dates[i].getTime()));

				writer.addDocument(document);
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (writer != null) {
				try {
					writer.close();
				} catch (CorruptIndexException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	// 设置日期
	private void setDates() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		try {
			dates = new Date[ids.length];
			dates[0] = sdf.parse("2015-02-15");
			dates[1] = sdf.parse("2015-03-01");
			dates[2] = sdf.parse("2015-05-18");
			dates[3] = sdf.parse("2015-09-05");
			dates[4] = sdf.parse("2015-12-15");
			dates[5] = sdf.parse("2015-08-29");
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}

	// 新增范围检索-- TermRangeQuery
	public void searchByTermRang(String field, String start, String end, int num) {
		IndexSearcher searcher = getSearcher();
		// 最后两个参数表示起始和结尾是开区间还是闭区间，为什么我使用true或者false都无效？都是前闭后开
		Query query = TermRangeQuery.newStringRange(field, start, end, true, true);
		try {
			TopDocs tds = searcher.search(query, num);
			System.out.println("总共查询了： " + tds.totalHits);
			for (ScoreDoc sd : tds.scoreDocs) {
				Document doc = searcher.doc(sd.doc);
				System.out.println("id号：" + doc.get("id") + "，名字：" + doc.get("name") + "，邮箱：" + doc.get("email")
						+ "，附件条数：" + doc.get("attach") + "，日期：" + doc.get("date"));
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	// 新增(Int)范围检索-- IntPoint.newRangeQuery
	public void searchByNumricRange(String field, int start, int end, int num){
	    IndexSearcher searcher = getSearcher();
	    //这里前后都是闭区间，这里设置最后两个参数却有有效了
	    Query query = IntPoint.newRangeQuery(field, start, end);
	    try {
	        TopDocs tds = searcher.search(query, num);
	        System.out.println("总共查询了： " + tds.totalHits);
	        for(ScoreDoc sd : tds.scoreDocs){
	            Document doc = searcher.doc(sd.doc);
	            System.out.println("id号：" + doc.get("id") 
	                    + "，名字：" + doc.get("name") 
	                    + "，邮箱：" + doc.get("email")
	                    + "，附件条数：" +doc.get("attach") 
	                    + "，日期：" + doc.get("date"));
	        }
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	}
	// 前缀搜索 PrefixQuery
	public void searchByPrefix(String field, String value, int num){
	    IndexSearcher searcher = getSearcher();
	    Query query = new PrefixQuery(new Term(field, value));//value的值通过前缀匹配
	    try {
	        TopDocs tds = searcher.search(query, num);
	        System.out.println("总共查询了： " + tds.totalHits);
	        for(ScoreDoc sd : tds.scoreDocs){
	            Document doc = searcher.doc(sd.doc);
	            System.out.println("id号：" + doc.get("id") 
	                    + "，名字：" + doc.get("name") 
	                    + "，邮箱：" + doc.get("email")
	                    + "，附件条数：" +doc.get("attach") 
	                    + "，日期：" + doc.get("date"));
	        }
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	}
	// 通配符搜索 WildcardQuery
	public void searchByWildCard(String field, String value, int num){
	    IndexSearcher searcher = getSearcher();
	    Query query = new WildcardQuery(new Term(field, value));
	    try {
	        TopDocs tds = searcher.search(query, num);
	        System.out.println("总共查询了： " + tds.totalHits);
	        for(ScoreDoc sd : tds.scoreDocs){
	            Document doc = searcher.doc(sd.doc);
	            System.out.println("id号：" + doc.get("id") 
	                    + "，名字：" + doc.get("name") 
	                    + "，邮箱：" + doc.get("email")
	                    + "，附件条数：" +doc.get("attach") 
	                    + "，日期：" + doc.get("date"));
	        }
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	}
	
	// 多条件查询
	public void searchByBoolean(int num){
	    IndexSearcher searcher = getSearcher();
	    BooleanQuery.Builder  builder=new BooleanQuery.Builder();
	    //下面的查询表示名字为tom同时内容中有like的索引
	    builder.add(new TermQuery(new Term("name", "tom")), Occur.MUST);//最后的参数表示条件必须有，如果是MUST_NOT表示必须没有
	    builder.add(new TermQuery(new Term("emails", "aa@qq.com")), Occur.MUST);//如果是SHOULD表示可有可无
	    
	    BooleanQuery  query = builder.build();
	    try {
	        TopDocs tds = searcher.search(query, num);
	        System.out.println("总共查询了： " + tds.totalHits);
	        for(ScoreDoc sd : tds.scoreDocs){
	            Document doc = searcher.doc(sd.doc);
	            System.out.println("id号：" + doc.get("id") 
	                    + "，名字：" + doc.get("name") 
	                    + "，邮箱：" + doc.get("email")
	                    + "，附件条数：" +doc.get("attach") 
	                    + "，日期：" + doc.get("date"));
	        }
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	}
	
	// 短语查询
	public void searchByPhrase(int num){
        IndexSearcher searcher = getSearcher();
        PhraseQuery.Builder builder = new PhraseQuery.Builder();
        //比如I like football，我们查询I football则表示中间有一跳（一空），参数值就表示跳数
        builder.setSlop(1);
        builder.add(new Term("names", "a"));//注意：这里的参数值要小写，但是也会将大写的查出来
        builder.add(new Term("names", "tom"));
        PhraseQuery query = builder.build();
        try {
            TopDocs tds = searcher.search(query, num);
            System.out.println("总共查询了： " + tds.totalHits);
            for(ScoreDoc sd : tds.scoreDocs){
                Document doc = searcher.doc(sd.doc);
                System.out.println("id号：" + doc.get("id") 
                        + "，名字：" + doc.get("name") 
                        + "，邮箱：" + doc.get("email")
                        + "，附件条数：" +doc.get("attach") 
                        + "，日期：" + doc.get("date"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
	
	// 模糊查询
	public void searchByFuzzy(int num){
        IndexSearcher searcher = getSearcher();
        //这里我们看到名字虽然写错了，但是能够查出来，默认可以匹配一个字符出错的情况，这里设置匹配力（相似度）为0.5<=1，距离为2
        FuzzyQuery query = new FuzzyQuery(new Term("name", "tome"), 1, 2);
        try {
            TopDocs tds = searcher.search(query, num);
            System.out.println("总共查询了： " + tds.totalHits);
            for(ScoreDoc sd : tds.scoreDocs){
                Document doc = searcher.doc(sd.doc);
                System.out.println("id号：" + doc.get("id") 
                        + "，名字：" + doc.get("name") 
                        + "，邮箱：" + doc.get("email")
                        + "，附件条数：" +doc.get("attach") 
                        + "，日期：" + doc.get("date"));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }







}
